package com.aldobucchi.x.flash.geom.decompose
{
	
	
	import flash.geom.Matrix;
	import flash.geom.Point;
	
	import com.aldobucchi.x.Math.MathUtil;
	
	
	/**
	 * 
	 * http://en.wikipedia.org/wiki/Eigenvalue,_eigenvector_and_eigenspace
	 * 
	 * @author aldo.bucchi@gmail.com
	 * 
	 */	
	public class EigenValueDecomposition
	{
	
	
	
		public var value1:Number;
		
		public var value2:Number;
		
		public var vector1:Point;
		
		public var vector2:Point;
	
	
	
	
		public function EigenValueDecomposition( value1:Number, value2:Number, vector1:Point, vector2:Point )
		{

			this.value1 = value1;

			this.value2 = value2;

			this.vector1 = vector1;

			this.vector2 = vector2;
		}
		
		
		
		
		public static function decompose( matrix:Matrix ):EigenValueDecomposition
		{
			

			var m:Matrix 	= matrix,
				b:Number 	= -m.a - m.d,
				c:Number 	= m.a * m.d - m.b * m.c,
				d:Number 	= Math.sqrt(b * b - 4 * c),
				l1:Number 	= -(b + (b < 0 ? -d : d)) / 2,
				l2:Number 	= c / l1,
				vx1:Number 	= m.b / (l1 - m.a), vy1:Number = 1,
				vx2:Number 	= m.b / (l2 - m.a), vy2:Number = 1;
				

			if( MathUtil.eqFP(l1, l2) )
			{
				vx1 = 1, vy1 = 0, vx2 = 0, vy2 = 1;
			}
			
			if(!isFinite(vx1))
			{
				vx1 = 1, vy1 = (l1 - m.a) / m.b;
				if(!isFinite(vy1))
				{
					vx1 = (l1 - m.d) / m.c, vy1 = 1;
					if(!isFinite(vx1)){
						vx1 = 1, vy1 = m.c / (l1 - m.d);
					}
				}
			}
			
			if(!isFinite(vx2))
			{
				vx2 = 1, vy2 = (l2 - m.a) / m.b;
				if(!isFinite(vy2))
				{
					vx2 = (l2 - m.d) / m.c, vy2 = 1;
					if(!isFinite(vx2))
					{
						vx2 = 1, vy2 = m.c / (l2 - m.d);
					}
				}
			}
			
			var d1:Number 	 = Math.sqrt(vx1 * vx1 + vy1 * vy1),
				d2:Number 	 = Math.sqrt(vx2 * vx2 + vy2 * vy2);
				
				
			if(!isFinite(vx1 /= d1)){ vx1 = 0; }
			if(!isFinite(vy1 /= d1)){ vy1 = 0; }
			if(!isFinite(vx2 /= d2)){ vx2 = 0; }
			if(!isFinite(vy2 /= d2)){ vy2 = 0; }
			
			
			
			return new EigenValueDecomposition(
					l1,
					l2,
					new Point( vx1, vy1 ),
					new Point( vx2, vy2 )
				);
			
		}		
		
		
		
		

	
	}

}